#include "Noeud.h"
#include "Balise.h"

Balise::Balise(string unNom, bool baliseSimple) /*: Noeud((nodeType (BALISE)))*/ {
	int pos = unNom.find_first_of(":");
	if (pos != (int)std::string::npos) {
		espaceNom = "";
		nom = "";
		for (int i = 0 ; i < pos ; i++) {
			espaceNom += unNom[i];
		}
		for (unsigned int i = pos + 1 ; i < unNom.length() ; i++) {
			nom += unNom[i];
		}
	} else {
		nom = unNom;
		espaceNom = "";
	}

	simple = baliseSimple;
	fils = list<Noeud*>();
	attributs = vector<Attribut*>();
}

Balise::~Balise(){
	while (!fils.empty()) { //delete fils
		delete fils.back();
		fils.pop_back();
	}
	while (!attributs.empty()) { //delete attributs
		delete attributs.back();
		attributs.pop_back();
	}
}

string Balise::getNom(){
	return this->nom;
}

string Balise::getEspaceNom() {
	return this->espaceNom;
}

bool Balise::hasEspaceNom() {
	return !this->espaceNom.empty();
}

string Balise::getNomAvecEspace() {
	if (espaceNom == "")
		return this->nom;
	else //espace de nom
		return (this->espaceNom + ":" + this->nom);
}

bool Balise::estSimple(){
	return simple;
}

/*bool Balise::estBalise() {
	return true;
} */

NoeudType Balise::getType() {
	return BALISE_e;
}

const list<Noeud*>& Balise::getFils() {
	return this->fils;
}

list<Balise*> Balise::getListeBaliseFils() {
	list<Balise*> listeBalise;
	for (NoeudIterator noeudIt = this->fils.begin() ; noeudIt != this->fils.end() ; ++noeudIt) {
		if ((*noeudIt)->getType() == BALISE_e) {
			listeBalise.push_back((Balise*)*noeudIt);
		}
	}

	return listeBalise;
}

bool Balise::findFils(Noeud* unNoeud, list<Noeud*>::iterator &position) {
	for (list<Noeud*>::iterator it = fils.begin() ; it != fils.end() ; ++it) {
		if ((*it) == unNoeud) {
			position = it;
			return true;
		}
	}

	return false; //pas trouvé
}

void Balise::ajouterFils(Noeud* monfils){
	monfils->setPere(this);
	fils.push_back(monfils);
}

bool Balise::ajouterFilsApres(Noeud* nouveauFils, Noeud* noeudPrecedent) {
	list<Noeud*>::iterator position;
	if (!this->findFils(noeudPrecedent, position))
		return false;

	this->fils.insert(++position, nouveauFils);
	return true;
}

void Balise::ajouterListeFils(list<Noeud*>* uneListeFils) {
	for (list<Noeud*>::iterator it = uneListeFils->begin() ; it != uneListeFils->end() ; ++it) {
		this->fils.push_back(*it);
	}
}

bool Balise::ajouterListFilsApres(list<Noeud*>* uneListeFils, Noeud* noeudPrecedent) {
	list<Noeud*>::iterator position;
	if (!this->findFils(noeudPrecedent, position))
		return false;

	++position; //l'iterateur doit pointer sur l'objet avant lequel on doit inserer
	for (list<Noeud*>::iterator addIt = uneListeFils->begin() ; addIt != uneListeFils->end() ; ++addIt) {
		this->fils.insert(position, *addIt);
	}
	return true;
}

/* Supprimer un noeud fils */
bool Balise::detacherFils(Noeud *unFils) {
	for (list<Noeud*>::iterator it = this->fils.begin() ; it != this->fils.end() ; ++it) {
		if ((*it) == unFils) {
			fils.erase(it);
			return true;
		}
	}

	return false; //noeud pas trouvé
}

/* Renvoie une copie profonde */
Noeud* Balise::getCopieProfonde() {
	Balise* copie = new Balise(this->getNomAvecEspace(), this->simple);

	for (list<Noeud*>::iterator it = fils.begin() ; it != fils.end() ; ++it) {
		copie->ajouterFils((*it)->getCopieProfonde());
	}

	for (vector<Attribut*>::iterator it = attributs.begin() ; it != attributs.end() ; ++it) {
		Attribut* copieAttribut = new Attribut((*it)->getNom(), (*it)->getValeur());
		copie->ajouterAttribut(copieAttribut);
	}

	return copie;
}

void Balise::ajouterAttribut(Attribut* unAttribut) {
	attributs.push_back(unAttribut);
}

void Balise::ajouterAttributs(vector<Attribut*>* uneListeAttributs) {
	for (AttributIterator attIt = uneListeAttributs->begin() ; attIt != uneListeAttributs->end() ; ++attIt) {
		this->ajouterAttribut(*attIt);
	}
}

vector<string> Balise::getNomsAttributs() {
	vector<string> listeNomAttributs;
	for (AttributIterator attIt = this->attributs.begin() ; attIt != this->attributs.end() ; ++attIt) {
		listeNomAttributs.push_back((*attIt)->getNom());
	}

	return listeNomAttributs;
}

Attribut* Balise::getAttributWithName(string unNom) {
	for (AttributIterator it = this->attributs.begin() ; it != this->attributs.end() ; ++it) {
		if ((*it)->getNom().compare(unNom) == 0) 
			return *it;
	}
	return NULL;
}

const vector<Attribut*>& Balise::getAttributs() {
	return this->attributs;
}

string Balise::toString(int nbTab) {
	string s ("");
	//balise d'ouverture
	for (int i = 0 ; i< nbTab ; i++)
		s += "\t";
	s += "<";
	if (this->hasEspaceNom())
	{
		s += espaceNom;
		s += ":";
	}
	s += this->nom;

	// ajout des attributs
	for (AttributIterator attIt = this->attributs.begin() ; attIt != this->attributs.end() ; ++attIt) {
		s += " ";
		s += (*attIt)->toString();
	}

	if (this->simple) {
		s += "/>";
	} else { //double balise
		s += ">\n";
		for (NoeudIterator noeudIt = this->fils.begin() ; noeudIt != this->fils.end() ; ++noeudIt) {
			s += (*noeudIt)->toString(nbTab+1);
			s += "\n";
		}
		for (int i = 0 ; i< nbTab ; i++)
			s += "\t";

		s += "</";
		if (this->hasEspaceNom())
		{
			s += espaceNom;
			s += ":";
		}
		s += this->nom;
		s += ">";
	}

	return s;
}

string Balise::getRegexExp() {
	if (espaceNom == "")
		return this->nom;
	else //espace de nom
		return (this->espaceNom + ":" + this->nom);
}

string Balise::getFilsExpForRegex() {
	string exp = "";
	for (NoeudIterator noeudIt = this->fils.begin() ; noeudIt != this->fils.end() ; ++noeudIt) {
		exp += (*noeudIt)->getRegexExp();
		exp += ";";
	}

	return exp;
}